package analiseSintatica.Regras.Funcao;

import java.util.LinkedList;

import AnaliseLexicaFinal.EstruturaDeDados.LinkToken;
import analiseSemantica.ErroSemantico;
import analiseSemantica.Tipos.TiposSemanticos;
import analiseSemantica.estruturadedados.Funcao;
import analiseSemantica.estruturadedados.Token;
import analiseSintatica.AnalisadorSintatico;
import analiseSintatica.ErroSintaticoException;
import analiseSintatica.Regras.Regra;

public class RegraChamadaFuncao extends Regra {

    //<chamada_funcao> := identificador "(" [<args_chamada>] ")"
    protected static Regra instancia;
    protected String estrutura = "identificador '(' [<args_chamada>] ')'";

    /**
     * Construtor privado necessario ao singleton
     */
    private RegraChamadaFuncao() {
    }

    /**
     * Retorna a unica instancia dessa classe.
     * @return
     */
    public static RegraChamadaFuncao getInstance() {
        if (instancia == null) {
            instancia = new RegraChamadaFuncao();
        }
        return (RegraChamadaFuncao) instancia;
    }

    @Override
    public TiposSemanticos analisar(LinkedList<LinkToken> listaTokens) throws ErroSintaticoException {

        TiposSemanticos tiposArgs = new TiposSemanticos();
        boolean funcao = false;
        
        LinkToken id = listaTokens.removeFirst();//remove o identificador
        Token funcaobusca = AnalisadorSintatico.escopoatual.find(id.getLexema());
        Funcao funcaob = null;
        if(funcaobusca == null){
        	AnalisadorSintatico.errosemanticos.add(new ErroSemantico("A Funcao "+id.getLexema()+" nao existe", id.getLinha()));
        }else if(!(funcaobusca instanceof Funcao)){
        	AnalisadorSintatico.errosemanticos.add(new ErroSemantico(id+" nao e uma funcao", id.getLinha()));
        }else{
        	funcao = true;
        	funcaob = (Funcao)funcaobusca;
        }
        reconheceLexema(listaTokens, "delimitador", "(", estrutura);

        if (listaContem(RegraArgsChamada.getInstance().getPrimeiro(), listaTokens.getFirst())) {
            tiposArgs = RegraArgsChamada.getInstance().analisar(listaTokens);
            if(funcao && tiposArgs != null){
            	if(funcaob.getTamanhoParamEntrada() != tiposArgs.size()){
            		AnalisadorSintatico.errosemanticos.add(new ErroSemantico("Numero de argumentos da funcao nao confere com a chamada", listaTokens.getFirst().getLinha()));
        		}else{
	            	for(int i = 0; i < funcaob.getTamanhoParamEntrada(); i++){
	            		
	            		if(!corresponde(funcaob.getParamEntrada(i), (String)tiposArgs.getTipo(i).getNomeTipo()))
	            			AnalisadorSintatico.errosemanticos.add(new ErroSemantico("Parametro "+(i+1)+" incompativel para "+(String)tiposArgs.getTipo(i).getNomeTipo(), tiposArgs.getTipo(i).getLinha()));
	            				
	            	}
        		}
            }
        }
        
        reconheceLexema(listaTokens, "delimitador", ")", estrutura);
        return null;
    }

    private static boolean corresponde(String variavel, String valor){
    	if(variavel.equals("int") && valor.equals("int"))
    		return true;
    	else if(variavel.equals("char") && valor.equals("char"))
    		return true;
    	else if(variavel.equals("boolean") && valor.equals("boolean"))
    		return true;
    	else if(variavel.equals("float") && valor.equals("float"))
    		return true;
    	else{
    		String ponteiro = isPonteiro(variavel);
    		if(ponteiro != null){
    			if(isTipoPrimitivo(ponteiro))
    				return ponteiro.equals(isEndereco(valor));
    			else
    				return ponteiro.equals(valor);
    		}
    		return false;
    	}
    }
    
    
    @Override
    protected void setPrimeiro() {
        this.primeiro.add("identificador");
    }
}
